package com.mc.fastkit.ext

import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

class InnerException(message: String = "inner value error") : Exception(message)

/**
 * 处理1对1关系，顺序执行后续的方法
 *
 * A->B->C
 * @receiver Result<V>
 * @param transform Function1<V?, Result<E?>>
 * @return Result<E?>
 */
@OptIn(ExperimentalContracts::class)
inline fun <V, E> Result<V>.andThen(transform: (V?) -> Result<E>): Result<E> {
    // kotlin 约定，告诉编译器 transform 最多执行一次
    contract {
        callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
    }
    return if (isSuccess) {
        transform(getOrNull())
    } else {
        Result.failure(exceptionOrNull() ?: InnerException())
    }
}

/**
 * 处理1对多关系
 *
 * A->{B、C}
 * @receiver Result<V>
 * @param transform Function1<V?, E?>
 * @return Result<E?>
 */
@OptIn(ExperimentalContracts::class)
inline fun <V, E> Result<V>.dispatch(transform: (V?) -> E): Result<E> {
    contract {
        callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
    }
    return if (isSuccess) {
        kotlin.runCatching { transform(getOrNull()) }
    } else {
        Result.failure(exceptionOrNull() ?: InnerException())
    }
}

/**
 * 处理多对1关系
 *
 * {A、B}->C
 * @param block Function0<V>
 * @return Result<V>
 */
@OptIn(ExperimentalContracts::class)
inline fun <V> zip(block: () -> V): Result<V> {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return runCatching { block() }
}

/**
 * 选择性关系，前面的方法返回失败后，继续执行后续的方法，成功后后续不再执行
 *
 * a().b().c()
 * @receiver Result<V>
 * @param block Function0<Result<V>>
 * @return Result<V>
 */
fun <V> Result<V>.or(block: () -> Result<V>): Result<V> {
    return when {
        isSuccess -> this
        else -> block()
    }
}